/*
 * Copyright 2011 Philippe Blanc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package me.l1k3.fx.client.channel;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;

import me.l1k3.core.client.Core;
import me.l1k3.fx.client.channel.impl.OpacityChannelImplJS;
import me.l1k3.fx.client.channel.inter.Channel;
import me.l1k3.fx.client.channel.inter.ChannelContext;
import me.l1k3.fx.client.channel.trait.Vector;
import me.l1k3.fx.client.engine.inter.FXEngine;

public abstract class OpacityChannel implements Channel {
    protected boolean forward;
    protected boolean accumulate;
    protected Vector opacity = new Vector();
	
	//- - - factory
    
    public final static OpacityChannel create(String type) {
        if (type.equals(FXEngine.JS)) {
            return new OpacityChannelImplJS();
        }
        
        return GWT.create(OpacityChannel.class);
    }
	
	public final static OpacityChannel range(String type) {
		return range(type, 1, 0);
	}
	
    public final static OpacityChannel range(String type, double start, double end) {
        OpacityChannel channel = create(type);
        channel.setRange(start, end);
        
        return channel;
    }
    
    public final static OpacityChannel smartRange(String type, Element element) {
        return smartRange(type, element, 1, 0);
    }
    
    public final static OpacityChannel smartRange(String type, Element element, double x, double y) {
        double opacity = Core.parseDouble(Core.getComputedStyleProperty(element, "opacity"), 2);              
        if(opacity==y) return range(type, y, x);
        
        return range(type, x, y);
    }
	
	public final static OpacityChannel fromCurrentToX(String type, Element element, double x) {
	    double opacity = Core.parseDouble(Core.getComputedStyleProperty(element, "opacity"), 2); 
		if(opacity==x) return null;
		
		return range(type, opacity, x);
	}
	
	public final static OpacityChannel fromXToCurrent(String type, Element element, double x) {
	    double opacity = Core.parseDouble(Core.getComputedStyleProperty(element, "opacity"), 2); 
        if(opacity==x) return null;
        
        return range(type, x, opacity);
    }
	
	public final static OpacityChannel byIncrement(String type, double diff) {
		OpacityChannel channel = create(type);
		channel.setDiff(diff);
		channel.setAccumulate(true);
		
		return channel;
	}
	
	//- - - Static helper
	
	@Deprecated
	public static void setOpacity(Element element, double opacity) {
	    Style style = element.getStyle();
	    style.setOpacity(opacity);
	    
	    if(opacity==0) {
	        style.setProperty("display", "none");
	    }
	}
	
	//- - -
	
	public final void setRange(double start, double end) {
	    opacity.setDirection(start, end);   
	}
	
	public final void setDiff(double diff) {
        opacity.set(diff);
    }
	
	public final void setAccumulate(boolean accumulate) {
        this.accumulate = accumulate;
    }
    
    protected final void setOpacity(ChannelContext context) {
        context.getStyle().setOpacity(opacity.get(forward));
        context.setVisible(forward);
    }
    
    //- - -
	
    @Override
    public final boolean isForward() {
        return forward;
    }
    
    @Override
    public void init(ChannelContext context) {
        //this improve the direction detection
        forward = opacity.getDirection();
        
        if(opacity.getStart()==0 || opacity.getEnd()==0) {
            context.enableShowAndHide();
            
            if(Core.getComputedStyleProperty(context.getElement(), "visibility").equals("hidden") || Core.getComputedStyleProperty(context.getElement(), "display").equals("none")) {
                forward = false;
            }
        }

        setOpacity(context);
    }
    
    @Override
    public void toggle(ChannelContext context) {
        if(!accumulate) {
            forward = !forward;
            setOpacity(context);
        }
	}
    
    /*
    @Override
    public void start(ChannelContext context) { }
    */
    
    /*
    @Override
    public void update(ChannelContext context) { }
    */
    
    @Override
	public void complete(ChannelContext context) {
		if(accumulate) {
            opacity.accumulate();
        }
		
		toggle(context);
	}
}